#include "Population.h"


Population::Population(Spectrum * sp, int size, int age, int tournamentGroup, float mutAmount, float croAmount)
	:
sp(sp), size(size), age(age), tournamentGroupSize(tournamentGroup), mutationAmount(mutAmount), crossAmount(croAmount)
{
	realSize = size - size*mutAmount - size*croAmount;

	for(int i=0;i<realSize;i++)
	{	
		genes.push_back(new Genotype(sp));
	}

}

void Population::Mutate()
{
	for(int i=0;i<size*mutationAmount;i++)
	{
		int fortune = rand()%genes.size();
		Genotype * g = new Genotype((*genes[fortune]));
		
		 
		
		if(g->MutatePositive())
			genes.push_back(g);
		else
		{
			g->MutateNegative();
			if(g->MutatePositive())
				genes.push_back(g);
			else
			genes.push_back(new Genotype(sp));
		}
		//genes[fortune] = g;
	}
}


void Population::Cross()
{
	for(int i=0;i<size*crossAmount;i++)
	{
		int fortune = rand()%genes.size();
		int fortune2 = rand()%genes.size();
		Genotype * child = genes[fortune]->Cross(genes[fortune2]);
		genes.push_back(child);
	}
}



void Population::Tournament()
{
	//Do optymalizacji

	std::vector<Genotype *> tempGenes;
	
	Genotype*  best = new Genotype(getBestGenotype());
	//printf("%d\n",		best->Evaluate());
	
	while(tempGenes.size()<size)
	{
		std::vector<int> choosen;
		choosen.reserve(tournamentGroupSize);

		while(choosen.size()<tournamentGroupSize)
		{
			int fortune = rand()%genes.size();
			choosen.push_back(fortune);
		}

		int nMax = 0;
		int max = genes[choosen[0]]->Evaluate();

		for(int i=0;i<tournamentGroupSize;i++)
			if(genes[choosen[i]]->Evaluate()>max)
			{	
				nMax=i;
				max=genes[choosen[i]]->Evaluate();
			}

			//Potencjalny blad
			tempGenes.push_back(genes[choosen[nMax]]);
			genes.erase(genes.begin() + choosen[nMax]);
	}

	genes = tempGenes;
	genes.push_back(best);
}

Genotype Population::getBestGenotype()
{
	int best=-1;
	int bestVal=-1;
	for (int i=0;i<genes.size();i++)
	{
		if(bestVal<genes[i]->Evaluate())
		{
			best=i;
			bestVal=bestVal < genes[i]->Evaluate() ?  genes[i]->Evaluate(): bestVal;
		}
	}
	return (* genes[best]);
}

void Population::Evolve()
{
	for (int actAge=0;actAge<age;actAge++)
	{
	////	Genotype*  best = new Genotype(getBestGenotype());
	//	printf("%d Best %d\n", actAge,getBestGenotype().Evaluate());
		Mutate();		
		Cross();
	//	printf("%d Best %d\n", actAge,getBestGenotype().Evaluate());
		//genes[TheBest()]->Print(); printf("\n");
		//genes[TheBest()]->PrintValues();
		
		Tournament();
		//genes.push_back(best);
		printf("%d Best %d\n", actAge,getBestGenotype().Evaluate());
		
	}

	/*bool ok=true;
	if(sp->answer.size()==genes[TheBest()]->chain.size())
		for(int i=0;i<sp->answer.size();i++)
		{
			if(genes[TheBest()]->chain[i].second!=sp->answer[i])
				ok=false;
		}
	else 
		ok=false;
	std::cout<<(ok?"OK":"FALSE")<<std::endl;*/
};